<?php

/**
 * Rights installer component class file.
 *
 * @author Christoffer Niska <cniska@live.com>
 * @copyright Copyright &copy; 2010 Christoffer Niska
 * @since 0.9.3
 */
class RInstaller extends CApplicationComponent {

    const ERROR_NONE = 0;
    const ERROR_QUERY_FAILED = 1;

    /**
     * @property array the roles assigned to users implicitly.
     */
    public $defaultRoles;

    /**
     * @property string the name of the superuser role.
     */
    public $superuserName;

    /**
     * @property string the name of the authenticated role.
     */
    public $authenticatedName;

    /**
     * @property string the name of the guest role.
     */
    public $guestName;

    /**
     * @property RAuthManager the authorization manager.
     */
    private $_authManager;

    /**
     * @property boolean whether Rights is installed.
     */
    private $_installed;

    /**
     * @property CDbConnection
     */
    public $db;

    /**
     * Initializes the installer.
     * @throws CException if the authorization manager or the web user
     * is not configured to use the correct class.
     */
    public function init() {
        parent::init();

        // Make sure the application is configured
        // to use a valid authorization manager.
        $authManager = Yii::app()->getAuthManager();
        if (($authManager instanceof RDbAuthManager) === false)
            throw new CException(Rights::t('install', 'Application authorization manager must extend the RDbAuthManager class.'));

        // Make sure the application is configured
        // to use a valid web user.
        $user = Yii::app()->getUser();

        //if( ($user instanceof RWebUser)===false )
        //	throw new CException(Rights::t('install', 'Application web user must extend the RWebUser class.'));

        $this->_authManager = $authManager;
        $this->db = $this->_authManager->db;
    }

    /**
     * Runs the installer.
     * @param boolean whether to drop tables if they exists.
     * @return boolean whether the installer ran successfully.
     */
    public function run() {

        // Get the table names.
        $itemTable = $this->_authManager->itemTable;
        $itemChildTable = $this->_authManager->itemChildTable;
        $assignmentTable = $this->_authManager->assignmentTable;
        $rightsTable = $this->_authManager->rightsTable;

        // Fetch the schema.
        $schema = file_get_contents(dirname(__FILE__) . '/../data/schema.sql');

        // Correct the table names.
        $schema = strtr($schema, array(
            'gxc_auth_item' => $itemTable,
            'gxc_auth_item_child' => $itemChildTable,
            'gxc_auth_assignment' => $assignmentTable,
            'gxc_rights' => $rightsTable,
        ));

        // Convert the schema into an array of sql queries.
        $schema = preg_split("/;\s*/", trim($schema, ';'));

        // Start transaction
        $txn = $this->db->beginTransaction();

        try {
            // Execute each query in the schema.
            foreach ($schema as $sql) {
                $command = $this->db->createCommand($sql);
                $command->execute();
            }

            // Insert the necessary roles.
            $roles = $this->getUniqueRoles();
            foreach ($roles as $roleName) {
                $sql = "INSERT INTO {$itemTable} (name, type, data)
                    VALUES (:name, :type, :data)";
                $command = $this->db->createCommand($sql);
                $command->bindValue(':name', $roleName);
                $command->bindValue(':type', CAuthItem::TYPE_ROLE);
                $command->bindValue(':data', 'N;');
                $command->execute();
            }

            // Assign the logged in user the superusers role.
            $sql = "INSERT INTO {$assignmentTable} (itemname, userid, data)
                VALUES (:itemname, :userid, :data)";
            $command = $this->db->createCommand($sql);
            $command->bindValue(':itemname', $this->superuserName);
            $command->bindValue(':userid', Yii::app()->getUser()->id);
            $command->bindValue(':data', 'N;');
            $command->execute();

            // All commands executed successfully, commit.
            $txn->commit();
            return self::ERROR_NONE;
        } catch (CDbException $e) {
            // Something went wrong, rollback.
            $txn->rollback();

            return self::ERROR_QUERY_FAILED;
        }
    }

    /**
     * Returns a list of unique roles names.
     * @return array the list of roles.
     */
    private function getUniqueRoles() {
        $roles = CMap::mergeArray($this->defaultRoles, array(
                    $this->superuserName,
                    $this->authenticatedName,
                    $this->guestName,
        ));
        return array_unique($roles);
    }

    /**
     * @return boolean whether Rights is installed.
     */
    public function getInstalled() {
        if ($this->_installed !== null) {
            return $this->_installed;
        } else {
            $schema = array(
                "SELECT COUNT(*) FROM {$this->_authManager->itemTable}",
                "SELECT COUNT(*) FROM {$this->_authManager->itemChildTable}",
                "SELECT COUNT(*) FROM {$this->_authManager->assignmentTable}",
                "SELECT COUNT(*) FROM {$this->_authManager->rightsTable}",
            );

            try {
                foreach ($schema as $sql) {
                    $command = $this->db->createCommand($sql);
                    $command->queryScalar();
                }

                $installed = true;
            } catch (CDbException $e) {
                $installed = false;
            }

            return $this->_installed = $installed;
        }
    }

}
